<?php

declare(strict_types=1);

namespace app\common\webdav\fs;

use app\admin\model\HomeUser;
use app\admin\model\StoragePath;
use app\common\service\StorageService;
use app\common\tools\PathTools;
use app\common\webdav\auth\backend\Model;
use app\common\webdav\properties\Handler;
use League\Flysystem\FileNotFoundException;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\INode;
use Sabre\Uri;
use think\facade\Log;
use League\Flysystem\Filesystem;
use Overtrue\Flysystem\Qiniu\QiniuAdapter;
use Overtrue\Flysystem\Qiniu\Plugins\FetchFile;
use Sabre\DAV\Auth\Plugin as AuthPlugin;
use League\Flysystem\Adapter\Ftp;
use League\Flysystem\Adapter\Local;
use Sabre\DAV\IProperties;
use Sabre\DAV\PropPatch;
use Sabre\DAVACL\ACLTrait;
use Sabre\DAVACL\IACL;
use think\facade\App;

/**
 * Base node-class.
 *
 * The node class implements the method used by both the File and the Directory classes
 *
 * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
 * @author Evert Pot (http://evertpot.com/)
 * @license http://sabre.io/license/ Modified BSD License
 */
abstract class Node implements INode, IProperties
{

    // use  ACLTrait;

    protected $currentModelPath = null;

    protected $modelUser = null;

    protected $propertiesHandler = null;

    protected $storageService = null;

    public function __construct(HomeUser $modelUser, StoragePath $current_model_path, $overrideName = null)
    {
        Log::debug('node request:' . $current_model_path->id . ' ' . $current_model_path->path);

        $this->currentModelPath = $current_model_path;

        $this->modelUser = $modelUser;

        $this->overrideName = $overrideName;

        $this->propertiesHandler = new Handler($current_model_path);
        Log::debug('初始化 storage service');
        $this->storageService = new StorageService($modelUser, false);
    }

    public function getCurrentModelPath()
    {
        return $this->currentModelPath;
    }

    /**
     * Returns the name of the node.
     *
     * @return string
     */
    public function getName()
    {
        if ($this->overrideName) {
            return $this->overrideName;
        }
        list(, $name) = Uri\split($this->currentModelPath->path);

        return $name;
    }

    /**
     * Renames the node.
     *
     * @param string $name The new name
     */
    public function setName($name)
    {
        Log::debug('call setName');
        if ($this->overrideName) {
            throw new Forbidden('This node cannot be renamed');
        }

        list($parentPath) = Uri\split($this->currentModelPath->path);
        list(, $newName) = Uri\split($name);

        $newPath = $parentPath . '/' . $newName;

        try {
            $this->currentModelPath->path = $newPath;
            $this->currentModelPath->save();
        } catch (FileNotFoundException $th) {
        }
    }

    /**
     * Returns the last modification time, as a unix timestamp.
     *
     * @return int
     */
    public function getLastModified()
    {
        try {
            return $this->currentModelPath->getOrigin('update_time');
        } catch (FileNotFoundException $th) {
        }
    }


    /**
     * Updates properties on this node.
     *
     * This method received a PropPatch object, which contains all the
     * information about the update.
     *
     * To update specific properties, call the 'handle' method on this object.
     * Read the PropPatch documentation for more information.
     */
    public function propPatch(PropPatch $propPatch)
    {
        $properties = $this->currentModelPath->properties;

        $propPatch->handleRemaining(function ($set_properties) use ($properties) {

            foreach ($set_properties as $property_name => $property_value) {
                $properties[$property_name] = $property_value;
            }

            $this->currentModelPath->properties = $properties;

            $this->currentModelPath->save();
            return true;
        });
    }

    /**
     * Returns a list of properties for this nodes.
     *
     * The properties list is a list of propertynames the client requested,
     * encoded in clark-notation {xmlnamespace}tagname
     *
     * If the array is empty, it means 'all properties' were requested.
     *
     * Note that it's fine to liberally give properties back, instead of
     * conforming to the list of requested properties.
     * The Server class will filter out the extra.
     *
     * @param array $properties
     *
     * @return array
     */
    public function getProperties($properties)
    {

        $original_properties = $this->currentModelPath->properties;
        foreach ($properties as  $property_name) {

            $property_value = $this->propertiesHandler->getProperty($property_name);

            if (!is_null($property_value)) {
                $original_properties[$property_name] = $property_value;
            }
        }

        return $original_properties;
    }
}
